package com.util;

import com.config.RedisPool;
import com.init.SpringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.io.*;
import java.util.Map;
import java.util.Set;

/**
 * @author haoya_Coding_one
 * @version 1.0
 * @create 2018/12/20 12:07
 * @description TODO redis工具类
 */
public class JedisUtil {
    private static Logger logger= LoggerFactory.getLogger(JedisUtil.class);
    private static JedisPool jedisPool;

    public static JedisPool getJedisPool() {
        if (jedisPool == null) {
            synchronized (JedisUtil.class) {
                if (jedisPool == null) {
                    jedisPool = SpringUtil.getBean(RedisPool.jedisPoolBeanName, JedisPool.class);
                }
            }
        }
        return jedisPool;
    }

    /**
     * 获得一个对象
     */
    public static Object get(String key) {
        Object obj = null;
        Jedis jedis = getJedisPool().getResource();
        try {
            obj = byte2Object(jedis.get(getKey(key)));
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return null;
        } finally {
            jedisPool.returnResource(jedis);
        }
        return obj;
    }

    /**
     * 判断对象是否存在
     */
    public static boolean isExist(String key) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.exists(key);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return false;
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 保存一个对象
     * outTime: 0-持久性key，永不过期，单位秒.
     */
    public static void save(String key, Object value, int outTime) {
        Jedis jedis = getJedisPool().getResource();
        try {
            jedis.set(getKey(key), object2Bytes(value));
            if (outTime != 0) {
                jedis.expire(getKey(key), outTime);// 设置过期时间
            }
        } catch (Exception e) {
            logger.error("===save key===" + key + "==="
                    + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 删除一个对象
     */
    public static Long del(String key) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.del(key);
            // return 1L;
        } catch (Exception e) {
            logger.error("===del key===" + key + "==="
                    + e.getLocalizedMessage());
            return null;
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 字节转化为对象
     */
    private static Object byte2Object(byte[] bytes) {
        if (bytes == null || bytes.length == 0)
            return null;
        try {
            ObjectInputStream inputStream;
            inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
            Object obj = inputStream.readObject();
            return (Object) obj;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对象转化为字节
     */
    private static byte[] object2Bytes(Object value) {
        if (value == null)
            return null;
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream outputStream;
        try {
            outputStream = new ObjectOutputStream(arrayOutputStream);
            outputStream.writeObject(value);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                arrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return arrayOutputStream.toByteArray();
    }

    private static byte[] getKey(String key) {
        return key.getBytes();
    }

    /**
     * 保存一个对象到队列尾部
     */
    public static void rpushObject(String key, Object value) {
        Jedis jedis = getJedisPool().getResource();
        try {
            byte[] result = object2Bytes(value);
            if (result != null && result.length > 0) {
                jedis.rpush(getKey(key), result);
            }
        } catch (Exception e) {
            logger.error("===rpushObject--key===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 从队列头部获取一个对象
     */
    public static Object lpopObject(String key) {
        Jedis jedis = getJedisPool().getResource();
        try {
            byte[] result = jedis.lpop(getKey(key));
            if (result != null && result.length > 0) {
                return byte2Object(result);
            }
        } catch (Exception e) {
            logger.error("===lpopObject--key===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }


    /**
     * 原子性递增，并返回该新值
     */
    public static long incr(String key) {
        Jedis jedis = getJedisPool().getResource();
        try {
            long result = jedis.incrBy(key, 1);
            return result;
        } catch (Exception e) {
            logger.error("===incr===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return -1;
    }

    /**
     * 原子性递增，并返回该新值
     * 可以设置有效时间
     */
    public static long incr(String key, int outTime) {
        Jedis jedis = getJedisPool().getResource();
        try {
            long result = jedis.incrBy(key, 1);
            if (outTime != 0) {
                jedis.expire(getKey(key), outTime);// 设置过期时间
            }
            return result;
        } catch (Exception e) {
            logger.error("===incr===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return -1;
    }

    /**
     * 原子性递增n，并返回该新值
     */
    public static long incrBy(String key, long num) {
        Jedis jedis = getJedisPool().getResource();
        try {
            long result = jedis.incrBy(key, num);
            return result;
        } catch (Exception e) {
            logger.error("===incrBy===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return -1;
    }

    /**
     * 原子性递减n，并返回该新值
     */
    public static long decr(String key, long num) {
        Jedis jedis = getJedisPool().getResource();
        try {
            long result = jedis.decrBy(key, num);
            return result;
        } catch (Exception e) {
            logger.error("===decr===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return -1;
    }

    /**
     * 原子性递减n，并返回该新值
     */
    public static long decrBy(String key, long n) {
        Jedis jedis = getJedisPool().getResource();
        try {
            long result = jedis.decrBy(key, n);
            return result;
        } catch (Exception e) {
            logger.error("===decrBy===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return -1;
    }

    public static boolean saveNxString(String key, String value, int outTime) {
        Jedis jedis = getJedisPool().getResource();
        try {
            Long result = jedis.setnx(key, value);
            if (outTime != 0) {
                jedis.expire(key, outTime);//设置过期时间
            }
            return result != null && result.longValue() == 1;
        } catch (Exception e) {
            logger.error("===setNxString===" + key + "===" + e.getLocalizedMessage());
            return false;
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 保存一个key和对应的value, value可以是数值型如"1"
     * outTime: 0-持久性key，永不过期，单位秒.
     */
    public static void saveString(String key, String value, int outTime) {
        Jedis jedis = getJedisPool().getResource();
        try {
            jedis.set(key, value);
            if (outTime != 0) {
                jedis.expire(key, outTime); // 设置过期时间
            }
        } catch (Exception e) {
            logger.error("===setString===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }


    /**
     * 获取一个key的String/int
     */
    public static String getString(String key) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.get(key);
        } catch (Exception e) {
            logger.error("===getString===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 保存一个map
     */
    public static void saveMap(String key, Map<String, String> hash) {
        Jedis jedis = getJedisPool().getResource();
        try {
            jedis.hmset(key, hash);
        } catch (Exception e) {
            logger.error("===setMap===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }


    /**
     * 获取一个map中的某一个值
     */
    public static String getMapOne(String key, String field) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.hget(key, field);
        } catch (Exception e) {
            logger.error("===getMap===" + key + ",field:" + field + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 获取map的所有key
     */
    public static Set<String> getMapKeys(String mapKey) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.hkeys(mapKey);
        } catch (Exception e) {
            logger.error("===getMapKeys===" + mapKey + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 获取map的所有key-value
     */
    public static Map<String, String> getMapKeyValues(String mapKey) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.hgetAll(mapKey);
        } catch (Exception e) {
            logger.error("===getMapKeyValues===" + mapKey + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 删除一个map
     */
    public static Set<String> delMap(String mapKey) {
        Jedis jedis = getJedisPool().getResource();
        try {
            Set<String> mapKeys = jedis.hkeys(mapKey);
            for (String str : mapKeys) {
                jedis.hdel(mapKey, str);
            }
        } catch (Exception e) {
            logger.error("===delMapKeys===" + mapKey + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 获取map的长度
     */
    public static long getMapLen(String mapKey) {
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.hlen(mapKey);
        } catch (Exception e) {
            logger.error("===getMapKeys===" + mapKey + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return 0;
    }

    /**
     * 删除某个map中的某个值
     */
    public static void delMapOne(String mapKey, String field) {
        Jedis jedis = getJedisPool().getResource();
        try {
            jedis.hdel(mapKey, field);
        } catch (Exception e) {
            logger.error("===getMap===" + mapKey + ",field:" + field + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }

    /**
     * 开启redis事物
     * 执行事物使用 Transaction对象的.exec()方法
     */
    public static Transaction multi(){
        Jedis jedis = getJedisPool().getResource();
        try {
            return jedis.multi();
        } catch (Exception e) {
            logger.error("===multi===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
        return null;
    }

    /**
     * 设置key的有效时间
     */
    public static void expire(String key, int outTime){
        Jedis jedis = getJedisPool().getResource();
        try {
            if (outTime != 0) {
                jedis.expire(getKey(key), outTime);// 设置过期时间
            }
        } catch (Exception e) {
            logger.error("===expire key===" + key + "===" + e.getLocalizedMessage());
        } finally {
            getJedisPool().returnResource(jedis);
        }
    }
}
